package com.hz.house.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.hz.house.bean.dto.CallHistoryDTO;
import com.hz.house.bean.dto.CallHistoryInfo;
import com.hz.house.bean.dto.PageDTO;
import com.hz.house.bean.entity.*;
import com.hz.house.bean.es.SellManEsDocumentBean;
import com.hz.house.bean.vo.*;
import com.hz.house.bean.vo.building.Building;
import com.hz.house.common.*;
import com.hz.house.config.TencentImMessageConfig;
import com.hz.house.dao.CallPhoneMapper;
import com.hz.house.dao.CustomerMapper;
import com.hz.house.dao.SellManMapper;
import com.hz.house.enums.BidTypeEnum;
import com.hz.house.enums.ScoreConsumeTypeEnum;
import com.hz.house.enums.SellManScoreEnum;
import com.hz.house.enums.SystemMsgEnum;
import com.hz.house.token.CurrentUser;
import com.hz.house.utils.ConverUtils;
import com.hz.house.utils.DaysIntUtil;
import com.hz.house.utils.im_sign.TlsSigature;
import com.hz.house.utils.im_sign.TlsSigature.GenTlsSignatureResult;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;

/**
 * <p>
 * 职业顾问
 *
 * @author lfw
 */
@Service
@Slf4j
public class SellManService {
    @Value("${encodePhoneCall}")
    private String encodePhoneCall;

    @Autowired
    private TencentImMessageConfig imConfig;

    @Autowired
    private RedisCacheDataService cacheService;

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private CustomerMapper userMapper;

    @Autowired
    private SellManMapper sellManMapper;
    @Autowired
    private CallPhoneMapper callPhoneMapper;

    @Autowired
    private ThreadPool threadPool;

    @Autowired
    private SellManScoreService sellManScoreService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private SysMsgService sysMsgService;

    @Autowired
    private PhoneCodeService phoneCodeService;

    @Resource
    private RestTemplate ribbonTemplate;

    @Resource
    private RestTemplate restTemplate;

    // 访问量统计SellManMapperExt
    private Map<Integer, Integer> sm_visits = new HashMap<>();
    // 咨询量统计
    private Map<Integer, Integer> sm_askCounts = new HashMap<>();
    // 点赞数统计
    private Map<Integer, Integer> sm_praise = new HashMap<>();
    //需要更新用户基本信息的批量处理
    private LinkedBlockingDeque<UserBaseInfo> needUpdateInfos = new LinkedBlockingDeque<>();

    // 定时跟新访问量，咨询量和点赞数到es，记录变动过的置业顾问
    private Set<Integer> sm_customerIds = new HashSet<>();

    @Autowired
    private ElasticsearchTemplate esTemplate;

    @Autowired
    private SellManCoinService sellManCoinService;

    //默认的用户头像
    private String defaultHeadImg = "https://housessmall-dev-index-img-1258778894."
            + "cos.ap-chengdu.myqcloud.com/sellman/headImg_xiong.png";

    public Object getImSellManInfo(Integer customerId) {

        if (customerId == null) {
            return ResultUtil.fail("咨询错误");
        }
        Map<String, Object> m = new HashMap<>();
        // 获取置业顾问的信息
        SellManCachedBasicInfoBean sellMan = cacheService.getSellManBasicInfo(customerId);
        m.put("sellMan", sellMan);
        // 统计咨询量
        addAskCounts(customerId);
        return ResultUtil.ok(m);
    }

    /**
     * 获取用户的名字头像等基本信息，签名
     *
     * @return
     */
    public Object getImCurrentUserInfo() {
        int myid = CurrentUser.getCurrentUserId();
        Map<String, Object> m = new HashMap<>();
        GenTlsSignatureResult res = TlsSigature.genSig(imConfig.getSdkAppId(), myid + "", imConfig.getSecretKey());
        m.put("urlSig", res.urlSig);
        CustomerBean u = this.customerMapper.getUserById(myid);
        Map<String, Object> uinfo = new HashMap<>();
        uinfo.put("customerId", myid);
        uinfo.put("name", u.getName() == null ? "用户" + myid : u.getName());
        uinfo.put("headImg", u.getHeadImg());
        m.put("currentUser", uinfo);
        return ResultUtil.ok(m);
    }

    /**
     * 点击主页，添加浏览量
     */
    public void addSellManVisits(Integer customerId) {
        if (customerId == null)
            return;
        synchronized (sm_visits) {// 保证计算的时候线程安全

            Integer vs = sm_visits.get(customerId);
            if (vs == null)
                sm_visits.put(customerId, getRadom(5, 10));
            else {
                vs += getRadom(5, 10);
                sm_visits.put(customerId, vs);
            }
        }
    }

    // 统计用户的
    private void addAskCounts(Integer customerId) {
        if (customerId == null)
            return;
        synchronized (sm_askCounts) {
            Integer vs = sm_askCounts.get(customerId);
            if (vs == null)
                sm_askCounts.put(customerId, 1);
            else {
                vs += 1;
                sm_askCounts.put(customerId, vs);
            }
        }
    }

    // 取随机值
    private int getRadom(int min, int max) {
        int x = new Random().nextInt(max - min) + min;
        return x;
    }

    public void startCountWorker() {
        CountWorker w = new CountWorker();
        Thread t = new Thread(w);
        t.start();
    }

    /**
     * 统计浏览量和询问数线程
     *
     * @author 10203
     */
    class CountWorker implements Runnable {

        @Override
        public void run() {

            while (true) {

                try {
                    //批量更新用户基本信息
                    batchUpdateUserBaseInfo();
                } catch (Exception e1) {
                }
                try {
                    // 处理增加浏览量
                    if (sm_visits.size() > 0) {
                        log.info("本次新增浏览量的置业顾问数量为:" + sm_visits.size());
                        synchronized (sm_visits) {
                            handleVisits();
                        }
                    } else
                        log.info("本次新增浏览量的置业顾问数量为0");
                    // 处理新增咨询次数
                    if (sm_askCounts.size() > 0) {
                        log.info("本次新增咨询数的置业顾问数量为:" + sm_askCounts.size());
                        synchronized (sm_askCounts) {
                            handleAskCount();
                        }
                    } else
                        log.info("本次新增咨询数的置业顾问数量为0");
                    // 处理新增的点赞数
                    if (sm_praise.size() > 0) {
                        log.info("本次新增点赞数的置业顾问数量为:" + sm_praise.size());
                        synchronized (sm_praise) {
                            handlePraisecount();
                        }
                    }
                } catch (Exception x) {
                    x.printStackTrace();
                    log.error("同步统计线程异常", x);
                } finally {
                    sm_visits.clear();
                    sm_askCounts.clear();
                    sm_praise.clear();
                }
                try {
                    Thread.sleep(30000);// 30秒一次循环处理数据
                } catch (InterruptedException e) {
                }
            }

        }

        private void handleVisits() {
            try {
                List<SimpleCountBean> x = new ArrayList<>();
                sm_visits.forEach((k, v) -> {
                    SimpleCountBean s = new SimpleCountBean();
                    s.setId(k);
                    s.setNum(v);
                    x.add(s);
                    addSmIds(k);
                });
                // 调用批量修改,使用线程池执行，否则影响正常业务
                threadPool.runInThreadPool(() -> {
                    sellManMapper.batchAddVisits(x);
                });
            } catch (Exception e) {
                log.error("批量修改置业顾问访问量异常", e);
                e.printStackTrace();
            }
        }

        private void handleAskCount() {
            try {
                List<SimpleCountBean> x = new ArrayList<>();
                sm_askCounts.forEach((k, v) -> {
                    SimpleCountBean s = new SimpleCountBean();
                    s.setId(k);
                    s.setNum(v);
                    x.add(s);
                    addSmIds(k);
                });
                // 调用批量修改,使用线程池执行，否则影响正常业务
                threadPool.runInThreadPool(() -> {
                    sellManMapper.batchAddAskCounts(x);
                });
            } catch (Exception e) {
                log.error("批量修改置业顾问咨询量异常", e);
                e.printStackTrace();
            }
        }

        private void handlePraisecount() {
            List<SimpleCountBean> x = new ArrayList<>();
            sm_praise.forEach((k, v) -> {
                SimpleCountBean s = new SimpleCountBean();
                s.setId(k);
                s.setNum(v);
                x.add(s);
                addSmIds(k);
            });
            // 调用批量修改,使用线程池执行，否则影响正常业务
            threadPool.runInThreadPool(() -> {
                sellManMapper.batchAddPaiseCounts(x);
            });
        }

        private void addSmIds(int id) {
            synchronized (sm_customerIds) {
                sm_customerIds.add(id);
            }
        }

        /**
         * 批量修改系统启动后用户的基本数据
         */
        private void batchUpdateUserBaseInfo() {
            log.info("本次需要更新用户的基本信息条数为:" + needUpdateInfos.size());
            if (needUpdateInfos.isEmpty())
                return;
            //异步执行
            threadPool.runInThreadPool(() -> {
                List<UserBaseInfo> batch = new ArrayList<>();
                //读取所有的缓存数据并删除
                while (!needUpdateInfos.isEmpty()) {
                    batch.add(needUpdateInfos.poll());
                }
                //读取完成之后，批量处理数据
                if (batch.size() == 0) return;
                int x = sellManMapper.updateUserBaseInfo(batch);
                log.info("本次成功更新" + x + "个用户的基本信息");
                //如果是置业顾问需要同步到es
                List<UserBaseInfo> sellmans = new ArrayList<>();
                batch.forEach(u -> {
                    if (!u.isSellMan()) return;
                    sellmans.add(u);
                });
                log.info("本次批量更基本数据，是置业顾问的数量为:" + sellmans.size());
                if (sellmans.size() == 0) return;
                //更新到ES
                BulkRequestBuilder bulk = esTemplate.getClient().prepareBulk();
                sellmans.forEach(s -> {
                    UpdateRequest u = new UpdateRequest();
                    u.id(s.getCustomerId().toString());
                    u.index(Constants.SELL_MAN_ES_INDEX_NAME);
                    u.type(Constants.SELL_MAN_ES_TYPE_NAME);
                    Map<String, Object> m = new HashMap<>();
                    m.put("headImg", s.getHeadImg());
                    u.doc(m);
                    bulk.add(u);
                });
                BulkResponse res = bulk.execute().actionGet();
                if (res.hasFailures())
                    log.error("批量更新置业顾问基本数据到es失败");
                log.info("更新基本数据到es成功，删除置业顾问相关缓存");
                //删除置业顾问的缓存及今日之心和首页的置业顾问，楼盘详情的管不了了
                cacheService.deleteAllSellManCache();
                cacheService.deleteYesterdayStars(null);
                cacheService.deleteGodenSellManCache();

            });
        }

    }

    /**
     * <p>
     * 获取昨日之星置业顾问
     *
     * @return
     */
    public Object getYesterdayStar() {

        List<SellManYesterdayStar> stars = this.cacheService.getYesterdayStars(null);
        if (stars == null) {
            // 初始化昨日之星
            updateYesterdayStar(null);
            stars = this.cacheService.getYesterdayStars(null);
        }
        return ResultUtil.ok(stars);
    }

    // 初始化昨日之星缓存
    public void updateYesterdayStar(Integer buildingId) {
        // 查询昨日积分记录表最高的三位
        try {
            int yesterDayDate = DaysIntUtil.getDays(new Date()) - 1;// 昨天
            List<SellManHuoYueDu> huoYueDu = this.sellManMapper.getYesterdayStarHuoYueDu(yesterDayDate, buildingId);
            if (huoYueDu.size() == 0) {
                this.cacheService.setYesterdayStars(new ArrayList<>(), null);
                return;
            }
            List<SellManYesterdayStar> star = this.sellManMapper.getYesterDayStarInfo(huoYueDu);
            if (star.size() == 0) {
                this.cacheService.setYesterdayStars(new ArrayList<>(), null);
                return;
            }
            // 设置活跃度
            for (SellManYesterdayStar s : star) {
                for (SellManHuoYueDu h : huoYueDu) {
                    if (s.getCustomerId().intValue() == h.getCustomerId().intValue()) {
                        s.setHuoYueDu(h.getHuoYueDu());
                        break;
                    }
                }
            }
            // 排序
            List<SellManYesterdayStar> rankList = star.stream().sorted((o1, o2) -> Integer.compare(o2.getHuoYueDu(), o1.getHuoYueDu())).collect(Collectors.toList());
            this.cacheService.setYesterdayStars(rankList, null);
        } catch (Exception e) {
            log.error("更新昨日之星异常", e);
            e.printStackTrace();
        }
    }

    /**
     * <p>
     * 获取置业顾问的列表
     *
     * @return
     */
    public Object getSellManList(String keyword, Integer page) {

        if (page == null || page == 0) {
            page = 1;
        }
        BoolQueryBuilder meta = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(keyword)) {
            return handleKeyword(meta, keyword, page);
        }
        long st = System.currentTimeMillis();
        // 处理用户是否是置业顾问，如果是,使用脚本排序
        int customerId = CurrentUser.getCurrentUserId();
        SortBuilder sort = null;
        if (this.cacheService.getSellManBasicInfo(customerId) != null) {
            Script sc = new Script(" if(doc['customerId'].value == " + customerId + ")" + " 	return 0;" + " else "
                    + " 	return doc['rank'].value;");
            sort = SortBuilders.scriptSort(sc, ScriptSortType.NUMBER).order(SortOrder.ASC);
        } else {
            sort = SortBuilders.fieldSort("rank").order(SortOrder.ASC);
        }

        Map<String, Object> res = doSearch(meta, sort, page, null);
        long total = (long) res.get("total");// 总条数
        List<Map<String, Object>> data = (List<Map<String, Object>>) res.get("data");
        List<SellManEsDocumentBean> rows = new ArrayList<>();
        this.buildData(data, rows);
        Map<String, Object> m = new HashMap<>();
        m.put("total", total);
        m.put("rows", rows);
        long ed = System.currentTimeMillis();
        log.info("本次分页查询耗时:" + (ed - st) + "ms!");
        return ResultUtil.ok(m);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    private Object handleKeyword(BoolQueryBuilder meta, String keyword, int page) {

        // 同时查询职业顾问名字和楼盘名字两个字段，符合得都返回
        meta.should(QueryBuilders.matchPhraseQuery("name", keyword));
        meta.should(QueryBuilders.matchPhraseQuery("buildingName", keyword));
        // 排序,按照名次排序
        SortBuilder sort = SortBuilders.fieldSort("rank").order(SortOrder.ASC);
        Map<String, Object> res = doSearch(meta, sort, page, null);
        long total = (long) res.get("total");// 总条数
        List<Map<String, Object>> data = (List<Map<String, Object>>) res.get("data");
        List<SellManEsDocumentBean> rows = new ArrayList<>();
        this.buildData(data, rows);
        Map<String, Object> m = new HashMap<>();
        m.put("total", total);
        m.put("rows", rows);
        return ResultUtil.ok(m);
    }

    // 将map数据构造成对象
    public void buildData(List<Map<String, Object>> data, List<SellManEsDocumentBean> rex) {
        if (data == null || data.size() == 0)
            return;
        data.forEach(d -> {
            SellManEsDocumentBean s = JSON.parseObject(JSON.toJSONString(d), SellManEsDocumentBean.class);
            rex.add(s);
        });
    }

    @SuppressWarnings({"rawtypes"})
    public Map<String, Object> doSearch(QueryBuilder query, SortBuilder sort, int page, String[] returnFileds) {

        SearchRequestBuilder req = esTemplate.getClient().prepareSearch(Constants.SELL_MAN_ES_INDEX_NAME)
                .setTypes(Constants.SELL_MAN_ES_TYPE_NAME);
        // 设置请查询体
        req.setQuery(query);
        // 设置排序
        if (sort != null)
            req.addSort(sort);
        // 设置分页
        if (page > 0)
            req.setFrom((page - 1) * 15).setSize(15);
        // 设置返回指定的字段
        if (returnFileds != null)
            req.setFetchSource(returnFileds, null);
        SearchResponse rep = req.execute().actionGet();
        List<Map<String, Object>> all = new ArrayList<Map<String, Object>>();
        rep.getHits().forEach(h -> {
            Map<String, Object> res = h.getSourceAsMap();
            all.add(res);
        });
        Map<String, Object> res = new HashMap<String, Object>();
        res.put("total", rep.getHits().getTotalHits());
        res.put("data", all);
        return res;
    }

    public Object getUserRoleType() {
        int id = CurrentUser.getCurrentUserId();
        Map<String, Object> m = new HashMap<>();
        m.put("customerId", id);
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(id);
        if (sm != null) {
            m.put("role", "sell_man");
            m.put("buildingId", sm.getBuildingId());
        } else {
            m.put("role", "customer");
        }
        return ResultUtil.ok(m);
    }

    public Object addScoreOnSharePage(ShareAddScoreCondition sc) {
        if (sc.getSellManCustomerId() == null) {
            return ResultUtil.fail("职业顾问id为空");
        }
        if (sc.getScoreId() == null) {
            return ResultUtil.fail("加分项的id为空");
        }
        int scid = sc.getSellManCustomerId();
        if (this.cacheService.getSellManBasicInfo(scid) == null) {
            return ResultUtil.fail("该用户不是置业顾问");
        }
        SellManScoreEnum share = SellManScoreEnum.getSellManScoreEnumById(sc.getScoreId());
        if (share == null) {
            return ResultUtil.fail("该加分项不存在");
        }
//		if (sc.getShareDate() == null){
//			return ResultUtil.fail("转发的时间不能为空");
//		}
        int customerId = CurrentUser.getCurrentUserId();
        SellManScoreBean ssb = new SellManScoreBean();
        ssb.setCreateDate(new Date());
        ssb.setCustomerId(customerId);
        ssb.setDate(DaysIntUtil.getDays(ssb.getCreateDate()));
        ssb.setScore(share.getOnceScore());
        ssb.setScoreId(sc.getScoreId());
        ssb.setScoreName(share.getName());
        ssb.setSellManCustomerId(scid);
        // 异步加分
        this.threadPool.runInThreadPool(() -> {
            //加分 DaysIntUtil.getDays(sc.getShareDate())
            this.sellManScoreService.addScoreOnShare(ssb);
            //如果是置业顾问点击的，则通知用户置业顾问访问了他的主页
            if (SellManScoreEnum.SHARE_MYPAGE.getId() == ssb.getScoreId()) {
                customerService.sendVisitMsgToSellMan(ssb.getSellManCustomerId(), ssb.getCustomerId());
            }
        });
        return ResultUtil.ok();
    }

    public List<Integer> getAllSellManIds() {
        try {
            return this.sellManMapper.getAllSellManCustomerId();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询所有置业顾问id异常:", e);
            return new ArrayList<>();
        }
    }

    /**
     * 置业顾问签到接口
     *
     * @return
     */
    public Object sellmanSign() {

        int cid = CurrentUser.getCurrentUserId();
        if (this.cacheService.getSellManBasicInfo(cid) == null) {
            return ResultUtil.fail("您还不是置业顾问");
        }
        // 执行插入签到记录，如果今天重复签到，则抛出key冲突异常，表示失败
        SellManSignRecordBean ssr = new SellManSignRecordBean();
        ssr.setCreateTime(new Date());
        ssr.setSellManCustomerId(cid);
        ssr.setSignDate(DaysIntUtil.getDays(ssr.getCreateTime()));
        try {
            int index = this.sellManMapper.addSellManSignRecord(ssr);
            if (index > 0) {
                // 修改签到表最后签到时间和持续签到天数
                SellManSignBean ssbx = new SellManSignBean();
                ssbx.setLastSignDate(ssr.getSignDate());
                ssbx.setSeriesSignDays(1);
                ssbx.setSellManCustomerId(cid);
                int x = this.sellManMapper.updateSellManSign(ssbx);
                if (x > 0) {
                    doAfterSign(ssr.getSignDate(), cid);
                }
            }
            return ResultUtil.ok();
        } catch (Exception e) {
            return ResultUtil.fail("今天您已经签到了");
        }
    }

    // 签到后要做的事情，1、加分，2、如果是第30填，额外加分
    private void doAfterSign(int signDate, int sellManCustomerId) {
        // 执行签到加分
        SellManScoreBean ssb = new SellManScoreBean();
        ssb.setCreateDate(new Date());
        ssb.setCustomerId(0);
        ssb.setDate(signDate);
        ssb.setScore(SellManScoreEnum.SELL_MAN_SIGN.getOnceScore());
        ssb.setScoreId(SellManScoreEnum.SELL_MAN_SIGN.getId());
        ssb.setScoreName(SellManScoreEnum.SELL_MAN_SIGN.getName());
        ssb.setSellManCustomerId(sellManCustomerId);
        this.threadPool.runInThreadPool(() -> {
            this.sellManScoreService.addScoreOnSign(ssb);
            // 在线程池里执行
            // 如果是第30天，则加分
            int days = this.sellManMapper.getSignSeriesDays(sellManCustomerId);
            if (days == 0) {
                return;
            }
            // 对30取余，如果为0则+连续三十天积分
            if (days % 30 != 0) {
                return;
            }
            SellManScoreBean ssbx = new SellManScoreBean();
            ssbx.setCreateDate(new Date());
            ssbx.setCustomerId(0);
            ssbx.setDate(signDate);
            ssbx.setScore(SellManScoreEnum.SIGN_30_DAYS.getOnceScore());
            ssbx.setScoreId(SellManScoreEnum.SIGN_30_DAYS.getId());
            ssbx.setScoreName(SellManScoreEnum.SIGN_30_DAYS.getName());
            ssbx.setSellManCustomerId(sellManCustomerId);
            this.sellManScoreService.addScoreOnSign30Days(ssbx);
        });
    }

    /**
     * 查询置业顾问签到数据
     *
     * @return
     */
    public Object getSellmanSignInfo() {

        if (this.cacheService.getSellManBasicInfo(CurrentUser.getCurrentUserId()) == null)
            return ResultUtil.fail("您还不是置业顾问");

        SellManSignBean sign = this.sellManMapper.getSellManSignInfo(CurrentUser.getCurrentUserId());
        if (sign == null) {
            // 从未签到过
            sign = new SellManSignBean();
            sign.setLastSignDate(0);
            sign.setSellManCustomerId(CurrentUser.getCurrentUserId());
            sign.setSeriesSignDays(0);
        }

        Map<String, Object> m = new HashMap<>();
        m.put("sign_total", sign.getSeriesSignDays());
        int nowDate = DaysIntUtil.getDays(new Date());
        // 处理连续签到7天的数据
        int x = getSign7DaysData(sign.getSeriesSignDays(), sign.getLastSignDate(), nowDate);
        m.put("sign_7", x);
        // 今日是否已经签到,最后签到时间和今天相等，则已经签到，否则未签到
        m.put("today_isSign", nowDate == sign.getLastSignDate());
        // 是否可以开启宝箱
        boolean canOpen7Box = canOpenBox7(sign, nowDate, x);
        m.put("can_openbox", canOpen7Box);
        // 以这次的时间为boxid，开宝箱的时候带上来
        if (canOpen7Box)
            m.put("boxid", nowDate);
        return ResultUtil.ok(m);
    }

    // 当且仅当签到7天是7且没有开启过此次宝箱的才可以打开
    private boolean canOpenBox7(SellManSignBean sign, int nowDate, int sign7) {
        if (sign7 != 7) {
            return false;// 只有为7的时候才能开
        }
        int lastOpenDate = sign.getTreasureBox7LastDate();
        return lastOpenDate != nowDate;
    }

    // 处理连续七天签到数据,如果已经连续了7天，今天没签到的话，则置为0，开启下一轮，
    // 如果今天已经签到，则还没有到明天下一轮时间
    private int getSign7DaysData(int total, int lastSignDate, int nowDate) {
        if (total == 0) {
            return 0;
        }
        int x = total % 7;
        if (x == 0) {
            x = lastSignDate == nowDate ? 7 : 0;
        }
        return x;
    }

    /**
     * 开启七天签到宝箱
     *
     * @return
     */
    public Object openTreasureBox(Integer boxid) {
        if (boxid == null)
            return ResultUtil.fail("开启宝箱失败");
        int sellManCustomerId = CurrentUser.getCurrentUserId();
        if (this.cacheService.getSellManBasicInfo(sellManCustomerId) == null) {
            return ResultUtil.fail("您还不是置业顾问");
        }
        SellManSignBean sign = this.sellManMapper.getSellManSignInfo(CurrentUser.getCurrentUserId());
        if (sign == null) {
            return ResultUtil.fail("开启宝箱失败");
        }
        int series = sign.getSeriesSignDays();
        if (series == 0 || (series % 7) != 0) {
            log.info("连续签到的天数不够,开启宝箱失败!");
            ;
            return ResultUtil.fail("开启宝箱失败");
        }
        // 开启宝箱，修改最后开箱时间
        SellManSignBean s = new SellManSignBean();
        s.setSellManCustomerId(sellManCustomerId);
        s.setTreasureBox7LastDate(boxid);
        int nowDate = DaysIntUtil.getDays(new Date());
        if (nowDate != boxid) {
            return ResultUtil.fail("只有当天能打开宝箱");
        }
        // 这里是线程安全的
        int index = this.sellManMapper.updateLastOpenBox7Time(s);
        int score = getRadom(5, 36);
        if (index > 0) {
            // 执行加分动作
            SellManScoreBean ssb = new SellManScoreBean();
            ssb.setCreateDate(new Date());
            ssb.setCustomerId(0);
            ssb.setDate(nowDate);
            ssb.setScore(score);
            ssb.setScoreId(SellManScoreEnum.SIGN_7_DAYS.getId());
            ssb.setScoreName(SellManScoreEnum.SIGN_7_DAYS.getName());
            ssb.setSellManCustomerId(CurrentUser.getCurrentUserId());
            this.threadPool.runInThreadPool(() -> {
                this.sellManScoreService.addScoreOnSign7Days(ssb);
            });
            return ResultUtil.ok(null, score);
        } else {
            log.info("该宝箱已经开启过了");
            return ResultUtil.fail("本次宝箱已经开启过了");
        }

    }

    public void updateSellManSignSeries() throws Exception {
        try {
            int nowDate = DaysIntUtil.getDays(new Date());
            this.sellManMapper.updateSellManSeriesSign(nowDate);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("更新置业顾问连续签到天数异常", e);
            throw e;
        }
    }

    /**
     * 获取置业顾问今日任务的完成情况所有信息
     */
    public Object getDailyTaskCounts(int sellManCustomerId) {
        if (this.cacheService.getSellManBasicInfo(sellManCustomerId) == null) {
            return ResultUtil.fail("not_sellman");
        }
        Map<String, Object> m = new HashMap<>();
        // 查询今日是否已经签到
        Integer lastSignDate = this.sellManMapper.sellManTodayIsSign(sellManCustomerId);
        int nowDate = DaysIntUtil.getDays(new Date());
        if (lastSignDate == null || nowDate != lastSignDate) {
            m.put("today_isSign", false);
        } else {
            m.put("today_isSign", true);
        }
        // 是否已经关注了公众号，根据公众号是否已经加过分了来判断
        int scoreId = SellManScoreEnum.FOUCS_WXGZH_SELLMAN.getId();
        int isfocus = this.sellManMapper.sellManIsFocusWxgzh(sellManCustomerId, scoreId);
        if (isfocus > 0) {
            m.put("wxgzh_isFocus", true);
        } else {
            m.put("wxgzh_isFocus", false);
        }
        // 查询今日通过分享加分的记录次数人次
        Integer oldTotal = this.sellManMapper.getSellManTodayOldTimes(sellManCustomerId, nowDate);
        Integer newTotal = this.sellManMapper.getSellManInviteNewUserToday(sellManCustomerId, nowDate);
        m.put("new_user", newTotal == null ? 0 : newTotal);
        m.put("old_user", oldTotal == null ? 0 : oldTotal);
        return ResultUtil.ok(m);
    }

    /**
     * 一天可以给置业顾问点赞一次
     */
    public Object praiseSellMan(Integer sellManCustomerId) {
        if (sellManCustomerId == null) {
            return ResultUtil.fail("点赞失败");
        }
        if (this.cacheService.getSellManBasicInfo(sellManCustomerId) == null) {
            return ResultUtil.fail("点赞失败");
        }
        int nowDate = DaysIntUtil.getDays(new Date());
        int customerId = CurrentUser.getCurrentUserId();
        // 插入点赞记录
        SellManPraiseBean smp = new SellManPraiseBean();
        smp.setCreateTime(new Date());
        smp.setCustomerId(customerId);
        smp.setPraiseDate(nowDate);
        smp.setSellManCustomerId(sellManCustomerId);
        // 如果插入失败则表示已经点赞过了今天
        try {
            int index = this.sellManMapper.addSellManPraiseRecord(smp);
            if (index > 0) {
                // 更改总点赞数+1,由异步线程统一处理
                addPraise(sellManCustomerId);
            }
            return ResultUtil.ok(null, true);
        } catch (Exception e) {
            return ResultUtil.fail("已经点过赞了");
        }

    }

    private void addPraise(int sellManCustomerId) {
        if (sellManCustomerId == 0) {
            return;
        }
        synchronized (sm_praise) {
            Integer x = sm_praise.get(sellManCustomerId);
            if (x == null) {
                sm_praise.put(sellManCustomerId, 1);
            } else {
                sm_praise.put(sellManCustomerId, sm_praise.get(sellManCustomerId) + 1);
            }
        }
    }

    /**
     * 当前用户是否给置业顾问点赞了
     */
    public boolean isTodayPraiseSellMan(int customerId, int sellManCustomerId) {
        if (customerId == 0) {
            return false;
        }
        if (sellManCustomerId == 0) {
            return false;
        }
        int nowDate = DaysIntUtil.getDays(new Date());
        int index = this.sellManMapper.isTodayPraiseSellMan(customerId, sellManCustomerId, nowDate);
        return index > 0;
    }

    /**
     * 通过定时任务同步数据es
     */
    public void synSellManInfo2Es() {
        if (this.sm_customerIds.size() == 0) {
            log.info("本次同步更新到es的置业顾问数据为0");
            return;
        }

        long st = System.currentTimeMillis();
        // 跟新指定的置业顾问的浏览量，点赞数，咨询数到es
        List<Integer> ids = new ArrayList<>();
        synchronized (sm_customerIds) {
            sm_customerIds.forEach(id -> ids.add(id));
            sm_customerIds.clear();
        }
        List<SellManEsDocumentBean> sms = this.sellManMapper.getSellManSynInfo(ids);
        batchUpdateSellMan2Es(sms);
        long ed = System.currentTimeMillis();
        log.info("本次批量更新置业顾问的基础数据到es耗时:" + (ed - st) + "ms!共" + ids.size() + "条!");
    }

    private void batchUpdateSellMan2Es(List<SellManEsDocumentBean> sms) {
        BulkRequestBuilder bulk = this.esTemplate.getClient().prepareBulk();

        sms.forEach(s -> {
            UpdateRequest u = new UpdateRequest();
            u.id(s.getCustomerId().toString());
            u.index(Constants.SELL_MAN_ES_INDEX_NAME);
            u.type(Constants.SELL_MAN_ES_TYPE_NAME);
            Map<String, Object> m = new HashMap<>();
            m.put("visits", s.getVisits());
            m.put("askCount", s.getAskCount());
            m.put("praiseCounts", s.getPraiseCounts());
            u.doc(m);
            bulk.add(u);
        });
        BulkResponse res = bulk.execute().actionGet();
        if (res.hasFailures())
            log.error("批量更新数据到置业顾问es失败");
    }

    public Object focusSellMan(Integer sellManCustomerId, Boolean isFocus) {
        if (sellManCustomerId == null) {
            return ResultUtil.fail("关注失败");
        }
        int customerId = CurrentUser.getCurrentUserId();
        if (isFocus == null) {
            isFocus = false;
        }
        if (isFocus) // 取关
        {
            return doUnFocus(sellManCustomerId, customerId);
        }

        if (sellManCustomerId == customerId) {
            return ResultUtil.fail("不能关注自己哦");
        }
        if (this.cacheService.getSellManBasicInfo(sellManCustomerId) == null) {
            return ResultUtil.fail("该用户不是置业顾问");
        }
        SellManFocusBean smf = new SellManFocusBean();
        smf.setCreateDate(new Date());
        smf.setCustomerId(customerId);
        smf.setSellManCustomerId(sellManCustomerId);
        try {
            int index = this.sellManMapper.addSellManFocus(smf);
            if (index > 0) {
                doAfterFocus(customerId, sellManCustomerId);
                return ResultUtil.ok(null, true);
            } else {
                return ResultUtil.fail("关注失败");
            }
        } catch (Exception e) {
            return ResultUtil.fail("您已经关注了");
        }
    }

    private void doAfterFocus(int customerId, int sellManCustomerId) {
        this.threadPool.runInThreadPool(() -> {
            // 加分
            SellManScoreEnum sse = SellManScoreEnum.BE_FOCUSED;
            SellManScoreBean ssb = new SellManScoreBean();
            ssb.setCreateDate(new Date());
            ssb.setCustomerId(customerId);
            ssb.setDate(DaysIntUtil.getDays(ssb.getCreateDate()));
            ssb.setScore(sse.getOnceScore());
            ssb.setScoreId(sse.getId());
            ssb.setScoreName("置业顾问被关注加分");
            ssb.setSellManCustomerId(sellManCustomerId);
            this.sellManScoreService.addScoreOnBeFocused(ssb);
            // 发送系统消息
            customerService.focusSellManMsg(sellManCustomerId, customerId);
        });
    }

    // 取关，删除关注记录
    private Object doUnFocus(int sellManCustomerId, int customerId) {
        SellManFocusBean smf = new SellManFocusBean();
        smf.setCustomerId(customerId);
        smf.setSellManCustomerId(sellManCustomerId);
        this.sellManMapper.deleteSellManFocus(smf);
        return ResultUtil.ok(null, false);
    }

    public ResultBean addScoreOnReplyComment(Integer sellManCustomerId, Integer buildingId) {
        if (sellManCustomerId == null) {
            return ResultUtil.fail("置业顾问id为空");
        }
        if (buildingId == null) {
            return ResultUtil.fail("涉及的楼盘不能为空");
        }
        SellManScoreBean ssb = new SellManScoreBean();
        ssb.setCreateDate(new Date());
        ssb.setCustomerId(0);
        ssb.setDate(DaysIntUtil.getDays(ssb.getCreateDate()));
        ssb.setScore(SellManScoreEnum.BUILDING_COMMENT_REPLY.getOnceScore());
        ssb.setScoreId(SellManScoreEnum.BUILDING_COMMENT_REPLY.getId());
        ssb.setScoreName(SellManScoreEnum.BUILDING_COMMENT_REPLY.getName());
        ssb.setSellManCustomerId(sellManCustomerId);
        this.sellManScoreService.addScoreOnReplyComment(ssb, buildingId);
        return ResultUtil.ok();
    }

    public ResultBean getSellManBasicInfo(Integer sellManCustomerId) {
        if (sellManCustomerId == null) {
            return ResultUtil.fail("id为空");
        }
        SellManCachedBasicInfoBean x = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (x == null) {
            return ResultUtil.fail("不是置业顾问");
        }
        return ResultUtil.ok(x);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public Object getBuildingSellmans(Integer buildingId, Integer page) {
        if (buildingId == null) {
            return ResultUtil.fail("查询失败");
        }
        if (page == null) {
            page = 1;
        }
        QueryBuilder meta = QueryBuilders.termQuery("buildingId", buildingId);
        SortBuilder sort = SortBuilders.fieldSort("rank").order(SortOrder.ASC);
        Map<String, Object> res = doSearch(meta, sort, page, null);
        long total = (long) res.get("total");// 总条数
        List<Map<String, Object>> data = (List<Map<String, Object>>) res.get("data");
        List<SellManEsDocumentBean> rows = new ArrayList<>();
        this.buildData(data, rows);
        Map<String, Object> m = new HashMap<>();
        m.put("total", total);
        m.put("rows", rows);
        return ResultUtil.ok(m);
    }

    /**
     * 置业顾问个人页面的总积分活跃度以及今日积分
     *
     * @param sellManCustomerId
     * @return
     */
    public Object getScoreAndLive(Integer sellManCustomerId) {
        // 查询总积分及今日积分今日活跃度
        if (this.cacheService.getSellManBasicInfo(sellManCustomerId) == null) {
            return ResultUtil.fail("not_sellman");
        }
        int nowDate = DaysIntUtil.getDays(new Date());
        List<SellManTotalScoreAndLive> ssa = this.sellManMapper.getTotalScoreAndTodayScore(nowDate, sellManCustomerId);
        if (ssa.size() == 0) {
            return ResultUtil.fail("not_sellman");
        }
        // 长度只会为2
        SellManTotalScoreAndLive ssax = new SellManTotalScoreAndLive();
        for (SellManTotalScoreAndLive s : ssa) {
            if (s.getTodayScore() != null && s.getTodayScore() == -1)// 今日积分为-1，那么是总积分
                ssax.setTotalScore(s.getTotalScore() == null ? 0 : s.getTotalScore());
            if (s.getTotalScore() != null && s.getTotalScore() == -1) {// 总积分为-1，那么是今日积分
                ssax.setTodayScore(s.getTodayScore() == null ? 0 : s.getTodayScore());
                ssax.setTodayLive(ssax.getTodayScore());
            }
        }
        // 查询总活跃度，即最近一个月的总积分
        Integer live = this.sellManMapper.getLast30DaysTotalScore(sellManCustomerId, nowDate - 30);
        ssax.setTotalLive(live == null ? 0 : live);
        return ResultUtil.ok(ssax);
    }

    public Object getMonthScoreList(String yearMonth) {
        SimpleDateFormat mdf = new SimpleDateFormat("yyyy-MM");
        String st = null;
        String ed = null;
        if (StringUtils.isEmpty(yearMonth)) {
            // 查询本月1号到今天的记录
            Date now = new Date();
            st = mdf.format(now) + "-01";
            ed = mdf.format(now) + "-" + getLastDateOfMonth(now);
        } else {
            try {
                Date date = mdf.parse(yearMonth);
                st = mdf.format(date) + "-01";
                ed = mdf.format(date) + "-" + getLastDateOfMonth(date);
            } catch (ParseException e) {
                e.printStackTrace();
                return ResultUtil.fail("时间错误");
            }
        }
        // 分别计算开始日期的dayint和结束日的dayint
        int stDate = DaysIntUtil.getDays(st);
        int edDate = DaysIntUtil.getDays(ed);
        Map<String, Object> m = new HashMap<>();
        m.put("stDate", stDate);
        m.put("edDate", edDate);
        m.put("customerId", CurrentUser.getCurrentUserId());
        List<SellManDailyScoreBean> smds = this.sellManMapper.getMonthDailyScore(m);
        // 处理数据
        SimpleDateFormat ddf = new SimpleDateFormat("yyyy-MM-dd");
        smds.forEach(s -> {
            s.setTime(ddf.format(s.getDate()));
        });
        return ResultUtil.ok(smds);
    }

    private static int getLastDateOfMonth(Date date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(date);
        cl.add(Calendar.MONTH, 1);
        cl.set(Calendar.DATE, 1);// 设置成1号
        cl.add(Calendar.DATE, -1);// 减一天变上月最后一天
        return cl.get(Calendar.DATE);
    }

    /**
     * 查询每日的积分记录
     *
     * @param date
     * @param page
     * @return
     */
    public Object getDailyScoreRecord(String date, Integer page) {
        int dateInt = DaysIntUtil.getDays(date);
        if (page == null || page == 0)
            page = 1;
        Map<String, Object> m = new HashMap<>();
        m.put("date", dateInt);
        m.put("page", (page - 1) * 20);
        m.put("customerId", CurrentUser.getCurrentUserId());
        m.put("size", 20);
        List<SellManScoreRecord> x = this.sellManMapper.getDailyScoreRecord(m);
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        x.forEach(s -> {
            s.setShowTime(sdf.format(s.getCreateDate()));
        });
        int total = this.sellManMapper.getDailyScoreRecordTotal(m);
        m.clear();
        m.put("rows", x);
        m.put("total", total);
        return ResultUtil.ok(m);
    }

    public Object getLast30DaysLiveList(int customerId) {
        int nowDate = DaysIntUtil.getDays(new Date());
        int stDate = nowDate - 30;
        List<SellManDailyScoreBean> smds = this.sellManMapper.getLast30DailyScore(customerId, stDate);
        SimpleDateFormat ddf = new SimpleDateFormat("yyyy-MM-dd");
        smds.forEach(s -> {
            s.setTime(ddf.format(s.getDate()));
        });
        return ResultUtil.ok(smds);
    }


    /**
     * 查询用户是否有系统未读的消息
     *
     * @param customerId
     * @return
     */
    public Object getUserCenterNotReadSystemMsgCount(int customerId) {
        int notRead = this.sellManMapper.getNotReadMsgCount(customerId);
        return ResultUtil.ok(notRead > 0);
    }

    /**
     * 获取信息的同时，更新用户的基本信息
     *
     * @param customerId
     * @param info
     * @return
     */
    public Object getUserMsgAndPostBaseInfo(int customerId, UserBaseInfo info) {
        postUserInfo(customerId, info);
        int notRead = this.sellManMapper.getNotReadMsgCount(customerId);
        return ResultUtil.ok(notRead > 0);
    }

    private void postUserInfo(int customerId, UserBaseInfo info) {
        if (info == null) {
            return;
        }
        if (StringUtils.isEmpty(info.getHeadImg())) {
            return;
        }
        if (StringUtils.isEmpty(info.getNickName())) {
            return;
        }
        //处理成高清头像
        if (info.getHeadImg().equals("undefined") || info.getHeadImg().equals("null")) {
            info.setHeadImg(defaultHeadImg);
        } else {
            info.setHeadImg(getHeadImgUrl(info.getHeadImg()));
        }
        if (info.getNickName().equals("undefined") || info.getNickName().equals("null")) {
            String x = customerId + "";
            info.setNickName("用户" + (x.substring(2, x.length())));
        }
        //更新用户的基本信息，头像、昵称
        SellManCachedBasicInfoBean sellman = this.cacheService.getSellManBasicInfo(customerId);
        if (sellman != null) {
            //置业顾问，先对比用户头像是否变过，变了就不更新了
            if (!sellman.getHeadImg().equals(info.getHeadImg())) {
                info.setHeadImg(sellman.getHeadImg());
            }
            info.setSellMan(true);
        }
        info.setCustomerId(customerId);
        needUpdateInfos.offer(info);
    }

    private String getHeadImgUrl(String head) {
        if (StringUtils.isEmpty(head))
            return null;
        if (head.equals("undefined") || head.equals("null"))
            return null;
        //将url最后的132替换为0
        String url = head.substring(0, head.length() - 3) + "0";
        return url;
    }

    public Object notifyUserSendImMsg(Integer sellManCustomerId) {
        if (sellManCustomerId == null) {
            return ResultUtil.fail("发送失败");
        }
        this.threadPool.runInThreadPool(() -> this.sysMsgService.sendSellManZiXunMsg(sellManCustomerId));
        return ResultUtil.ok();
    }

    /**
     * 电话加密
     *
     * @param currentUserId
     * @param sellManCustomerId
     * @return
     */
    public Object encodePhoneNumber(Integer currentUserId, Integer sellManCustomerId) {
        if (Objects.isNull(sellManCustomerId)) {
            return ResultUtil.fail("发送失败");
        }
        // 可以发送消息，则查询发送者信息和置业顾问信息，进行模板消息推送
        SellManCachedBasicInfoBean x = this.cacheService.getSellManBasicInfo(sellManCustomerId);

        CustomerBean u = customerMapper.getUserById(currentUserId);

        //获取Redis中是否存在加密未打过电话的加密号码
        //TO DO something

        Integer nextId = callPhoneMapper.selectNextId();
        //编码本地电话号码、呼出电话号码
        String encodePhone = null;
        try {
            encodePhone = phoneCodeService.encodePhoneNumber("", x.getPhone(), encodePhoneCall, String.valueOf(nextId));
        } catch (Exception e) {
            return ResultUtil.fail(e.getMessage());
        }
        //将打电话编码记录放入Redis中
        //TO DO something

        //记录打电话
        CallPhoneBean callPhoneBean = new CallPhoneBean();
        callPhoneBean.setId(nextId);
        callPhoneBean.setLocalPhone("");
        callPhoneBean.setCreateDate(new Date());
        callPhoneBean.setStartTime(new Date());
        callPhoneBean.setConsumerId(currentUserId);
        callPhoneBean.setEncodePhone(encodePhone);
        callPhoneBean.setRemotePhone(x.getPhone());
        callPhoneBean.setSellmanId(sellManCustomerId);
        callPhoneMapper.insert(callPhoneBean);

        //放入线程池中执行发送消息模板
        this.threadPool.runInThreadPool(() -> {
            this.sysMsgService.encodePhoneNumber(currentUserId, sellManCustomerId);
        });
        return encodePhone;
    }

    /**
     * 查询通话记录
     *
     * @param currentUserId
     * @param pageIndex
     * @return
     */
    public CallHistoryInfo callMeHistoryLog(Integer currentUserId, boolean isAll, Integer pageIndex) {
        int pageSize = 20;
        PageHelper.startPage(pageIndex, pageSize, true);
        List<CallPhoneBean> beans = callPhoneMapper.selectBySellMan(currentUserId, isAll);
        PageInfo<CallPhoneBean> pageInfo = new PageInfo(beans);
        List<CallHistoryDTO> logs = new ArrayList<>();
        //查询分页信息
        for (CallPhoneBean bean : pageInfo.getList()) {
            CallHistoryDTO dto = new CallHistoryDTO();
            dto.setType(bean.getState());
            //是当天
            if (DaysIntUtil.getDays(bean.getStartTime()) == DaysIntUtil.getDays(new Date())) {
                dto.setDate(DaysIntUtil.dateToString(bean.getStartTime(), DaysIntUtil.HH$mm));
            } else {
                dto.setDate(DaysIntUtil.dateToString(bean.getStartTime(), DaysIntUtil.yyyy$MM$dd));
            }
            dto.setHoldTime(bean.getHoldTime());
            dto.setNumber(bean.getRemotePhone());
            CustomerBean u = customerMapper.getUserById(bean.getConsumerId());
            dto.setNickName(u.getName());
            logs.add(dto);
        }
        int dayTotal = callPhoneMapper.sumDayCallLog(currentUserId, null);
        //统计当天通话
        CallHistoryInfo info = new CallHistoryInfo(pageInfo.getTotal(), dayTotal, new PageDTO<>(pageInfo, logs));
        return info;
    }

    /**
     * 加密电话回调
     *
     * @param orderId
     * @param eventType
     * @param state
     * @param fee_time
     * @param hold_time
     * @param start_time
     * @param end_time
     * @param params
     * @param msg
     */
    public void encodePhoneCallBack(String orderId, String eventType, String state, String fee_time, String hold_time,
                                    String start_time, String end_time, String params, String msg) {
        CallPhoneBean callPhoneBean = new CallPhoneBean();
        try {
            callPhoneBean.setId(Integer.parseInt(params));
            callPhoneBean.setOrderId(orderId);
            callPhoneBean.setEventType(eventType);
            callPhoneBean.setState(ConverUtils.parseInt(state));
            callPhoneBean.setFeeTime(ConverUtils.parseInt(fee_time));
            callPhoneBean.setHoldTime(ConverUtils.parseInt(hold_time));
            if (Objects.equals("1", state)) {
                callPhoneBean.setStartTime(new Date(ConverUtils.parseLong(start_time) * 1000L));
                callPhoneBean.setEndTime(new Date(ConverUtils.parseLong(end_time) * 1000L));
            }
            callPhoneBean.setMsg(msg);
            callPhoneMapper.update(callPhoneBean);
        } catch (Exception e) {
            log.error("电话加密回调错误");
        }
    }


    public Object getUserRoleById(Integer customerId, Integer from) {
        if (customerId == null) {
            return ResultUtil.fail("错误");
        }
        SellManCachedBasicInfoBean info = this.cacheService.getSellManBasicInfo(customerId);
        Map<String, Object> m = new HashMap<>();
        if (info == null) {
            m.put("role", "customer");
            m.put("info", userMapper.getUserById(customerId));
            return ResultUtil.ok(m);
        }
        m.put("role", "sell_man");
        m.put("info", info);
        //获取置业顾问所属楼盘
        List<Integer> buildIds = new ArrayList<>();
        buildIds.add(info.getBuildingId());
        if (!ObjectUtils.isEmpty(info.getTwoBuildingId())) {
            buildIds.add(info.getTwoBuildingId());
        }
        List<Building> buildings = sellManMapper.getBuildingById(Joiner.on(",").join(buildIds));
        if (!StringUtils.isEmpty(from)) {
            buildings = buildings.stream().filter(building -> building.getId().equals(from)).collect(Collectors.toList());
        }
        m.put("buildings", buildings);
        return ResultUtil.ok(m);
    }

    public Object editSellManGreet(Integer customerId, String greet) {
        sellManMapper.editSellManGreet(customerId, greet);
        cacheService.deleteAllSellManCache();
        return ResultUtil.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    public Object scoreConvertCoin(Integer coin, Integer sellManCustomerId) throws Exception {
        if (coin == null || coin < 1)
            return ResultUtil.fail("兑换财富币数目不能小于1个");
        // 兑换比例为10积分=1个财富币
        Integer remainScore = this.sellManMapper.getSellManRemainScore(sellManCustomerId);
        if (remainScore == null)
            return ResultUtil.fail("not_sellman");
        if (coin * 10 > remainScore)
            return ResultUtil.fail("剩余积分不足");
        // 执行兑换积分 先扣减积分 再加金币
        this.sellManScoreService.minusScore(sellManCustomerId, coin * 10, ScoreConsumeTypeEnum.goldcoin);
        // 充值金币
        String description = "使用积分兑换财富币";
        sellManCoinService.addCoin(sellManCustomerId, coin, description);
        return ResultUtil.ok("兑换成功");
    }

    public Object getMyCoin(Integer sellManCustomerId) {

        // 先确定用户是不是置业顾问
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (sm == null)
            return ResultUtil.fail("not_sellman");
        Map<String, Object> m = new HashMap<>();
        m.put("headImg", sm.getHeadImg());
        // 查询财富币和可用积分
        SellManCoinAndRemainScore sc = this.sellManMapper.getSellManScoreAndCoin(sellManCustomerId);
        if (sc == null) {
            m.put("remainScore", 0);
            m.put("balance", 0);
            m.put("sellManCustomerId", 0);
            return ResultUtil.ok(m);
        }
        if (sc.getCoin() == null)
            sc.setCoin(0);
        if (sc.getRemainScore() == null)
            sc.setRemainScore(0);
        m.put("remainScore", sc.getRemainScore());
        m.put("balance", sc.getCoin());
        m.put("sellManCustomerId", sm.getCustormerId());
        return ResultUtil.ok(m);
    }

    public Object getCoinRecord(Integer page, Integer sellManCustomerId) {
        if (page == null || page < 1)
            page = 1;
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (sm == null)
            return ResultUtil.fail("not_sellman");
        Map<String, Object> m = new HashMap<>();
        Integer total = this.sellManMapper.getCoinRerodsTotal(sellManCustomerId);
        if (total == null || total == 0) {
            m.put("total", 0);
            m.put("rows", null);
            return ResultUtil.ok(m);
        }
        List<SellManCoinRecordBean> x = this.sellManMapper.getCoinRerods((page - 1) * 15, sellManCustomerId);
        m.put("total", total);
        m.put("rows", x);
        return ResultUtil.ok(m);
    }

    public void removeSellManCoinLockers() {
        coinLockers.clear();
    }

    //置业顾问竞价锁，晚上十一点删除，一个置业顾问一个对象，应该不会占用太多内存
    private Map<Integer, Object> coinLockers = new ConcurrentHashMap<>();

    /**
     * 置业顾问竞价，只能在23点前竞价，财富币不能少于5个，同时出价的金币不能大于余额。
     * 同时，出价者只能比最高出价高
     *
     * @param coin
     * @param sellManCustomerId
     * @return
     */
    public Object chuJia(Integer coin, Integer sellManCustomerId, Integer type) {
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (sm == null) {
            return ResultUtil.fail("not_sellman");
        }
        BidTypeEnum bidTypeEnum = BidTypeEnum.getByType(type);
        if (coin == null || coin.intValue() < bidTypeEnum.getLowest()) {
            return ResultUtil.fail("财富币不能少于5个哟");
        }
        Date now = new Date();
        if (isOverTime(now)) {
            log.info("出价时间超过23点了," + sellManCustomerId);
            return ResultUtil.fail("已超过23点");
        }
        // 加锁，防刷，防单用户并发影响余额判断
        Object locker = coinLockers.get(sellManCustomerId);
        coinLockers.put(sellManCustomerId, locker = new Object());
        synchronized (locker) {
            try {
                long st = System.currentTimeMillis();
                //要走两次数据库，没办法了 ，以后再优化
                // 判断余额是否充足
                if (!isHasBalance(sellManCustomerId, coin)) {
                    return ResultUtil.fail("您的余额不足");
                }
                //有bug隐患，暂无更好处理办法，先这样吧，希望不出问题
                //超过了最大值才能出价,这里只能放在这里，会将本次的出价设置为最高价，后续操作必须成功
                if (!this.cacheService.isExceedTodayMaxCoin(coin)) {
                    return ResultUtil.fail("出价不能低于当前最高价");
                }
                // 余额充足情况下执行新增或更改竞价记录，本次出价必须比上次出价高
                String homeDate = this.getHomePageDateStr();
                SellManHomePageRecordBean x = new SellManHomePageRecordBean();
                x.setCoin(coin);
                x.setCreateTime(now);
                x.setHomePageDate(homeDate);
                x.setIsSuccess(0);
                x.setBidType(bidTypeEnum.getType());
                x.setSellManCustomerId(sellManCustomerId);
                x.setUpdateTime(now);
                //入库
                int index = this.sellManMapper.doChuJia(x);
                log.info("index-" + sellManCustomerId + ":" + index);
                long ed = System.currentTimeMillis();
                log.info("处理置业顾问出价完成,耗时:" + (ed - st) + "ms!");
                return ResultUtil.ok("出价成功");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("置业顾问出价异常", e);
                return ResultUtil.fail("出价失败");
            }
        }

    }

    private String getHomePageDateStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cl = Calendar.getInstance();
        cl.add(Calendar.DATE, 1);
        return sdf.format(cl.getTime());
    }

    private boolean isHasBalance(int sellManCustomerId, int coin) {
        Integer balance = this.sellManMapper.getSellManCoinBalance(sellManCustomerId);
        return !(balance == null || balance < coin);
    }


    /**
     * 出价时间是否已经超过了晚上23点，超过了就不让再出价
     */
    private static boolean isOverTime(Date now) {
        // 将目标时间设置未23:00
        Calendar cl = Calendar.getInstance();
        cl.set(Calendar.HOUR_OF_DAY, 23);
        cl.set(Calendar.MINUTE, 0);
        cl.set(Calendar.SECOND, 0);
        // 将两个时间毫秒换算成秒再做对比
        long x = cl.getTime().getTime() / 1000L;
        long e = now.getTime() / 1000L;
        return !(e < x);
    }

    public Object getMyCoinAndTopCoinNow(Integer sellManCustomerId) {
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (sm == null)
            return ResultUtil.fail("not_sellman");
        Integer balance = this.sellManMapper.getSellManCoinBalance(sellManCustomerId);
        Integer maxCoin = this.cacheService.getNowMaxCoin();
        Map<String, Object> m = new HashMap<>();
        m.put("balance", balance == null ? 0 : balance);
        m.put("maxCoin", maxCoin == null ? 0 : maxCoin);
        m.put("sellManCustomerId", sellManCustomerId);
        return ResultUtil.ok(m);
    }

    public Object getTodayChuJiaRecord(Integer page, Integer sellManCustomerId) {
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (sm == null)
            return ResultUtil.fail("not_sellman");
        if (page == null || page < 1)
            page = 1;
        long st = System.currentTimeMillis();
        int total = this.sellManMapper.getTodayChuJiaListTotal(getHomePageDateStr());
        Map<String, Object> m = new HashMap<>();
        if (total == 0) {
            m.put("total", 0);
            m.put("rows", null);
            Integer balance = this.sellManMapper.getSellManCoinBalance(sellManCustomerId);
            m.put("balance", balance == null ? 0 : balance);
            m.put("homeDate", getHomePageDateStr());
            return ResultUtil.ok(m);
        }
        List<SellManHomePageRecordBean> list = this.sellManMapper
                .getTodayChuJiaList(getHomePageDateStr(), (page - 1) * 15);
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        list.forEach(r -> {
            r.setTime(sdf.format(r.getUpdateTime()));
            r.setUpdateTime(null);
        });
        m.put("total", total);
        m.put("rows", list);
        //还要查询我的财富币余额,第一页的时候才查询
        if (page == 1) {
            Integer balance = this.sellManMapper.getSellManCoinBalance(sellManCustomerId);
            m.put("balance", balance == null ? 0 : balance);
            m.put("homeDate", getHomePageDateStr());
        }
        long ed = System.currentTimeMillis();
        log.info("查询出价列表耗时：" + (ed - st) + "ms!");
        return ResultUtil.ok(m);
    }

    /**
     * 处理我要上首页的最终结果，扣减用户的金币，扣除成功则上首页成功，否则上首页失败，扣下一位,使用递归
     */
    public void handleGoToHomeResult(int maxCoin) {
        String homeDate = this.getHomePageDateStr();
        //查询出当前最高记录
        SellManHomePageRecordBean max = this.sellManMapper.getMaxCoinToday(homeDate, maxCoin);
        if (max == null) {
            if (maxCoin == 0)
                log.info("我要上首页结算-今日没有置业顾问出价");
            else
                log.info("我要上首页结算-已经没有出价的置业顾问可以结算了，其他人全部结算失败，金币不足");
            return;
        }
        //执行扣除金币，如果扣除失败，递归扣除下一位
        try {
            this.sellManCoinService.minusCoin(max.getSellManCustomerId(), max.getCoin(), "竞价我要上首页成功");
            //修改出价成功字段，结束
            int index = this.sellManMapper.updateHomePageRecordSuccess(homeDate, max.getSellManCustomerId());
            if (index > 0) {
                log.info("修改置业顾问竞价成功状态成功");
                //发送系统消息通知他
                afterHomePageMinusCoinSuccess(max, homeDate);
            } else
                log.info("修改置业顾问竞价成功状态失败");
        } catch (Exception e) {
            log.error("扣除我要上首页置业顾问金币失败", e);
            e.printStackTrace();
            afterHomePageMinusCoinFail(max, homeDate, e);
            //递归下一位
            handleGoToHomeResult(max.getCoin());
        }
    }

    private void afterHomePageMinusCoinSuccess(SellManHomePageRecordBean s, String homeDate) {
        this.sysMsgService.sendSysMsg(s.getSellManCustomerId(), "恭喜您,成功竞价置业顾问明日(" + homeDate + ")首页展示位!",
                "我要上首页竞价成功!", null, SystemMsgEnum.GOTO_HOMEPAGE);
    }

    private void afterHomePageMinusCoinFail(SellManHomePageRecordBean s, String homeDate, Exception e) {
        String msg = "";
        String title = "我要上首页竞价失败!";
        if (e instanceof BizExcepition)
            msg = "很遗憾,由于您财富币余额不足,竞价明日(" + homeDate + ")首页展示位失败!";
        else
            msg = "很抱歉,由于系统异常,您参与竞价明日(" + homeDate + ")首页展示位失败!";
        this.sysMsgService.sendSysMsg(s.getSellManCustomerId(), msg,
                title, null, SystemMsgEnum.GOTO_HOMEPAGE);
    }

    /**
     * 获取置业顾问个人主页的小程序二维码
     *
     * @return
     */
    public Object getSellManHomePageQRCodeBase64(int sellManCustomerId) {
        SellManCachedBasicInfoBean x = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (x == null)
            return ResultUtil.fail("not_sellman");
        try {
            byte[] img = this.getHomePageQRCode(sellManCustomerId);
            if (img == null || img.length == 0)
                return ResultUtil.fail("获取小程序码失败");
            String imgBase64 = new String(Base64.getEncoder().encode(img));
            Map<String, Object> m = new HashMap<>();
            m.put("qrcode", imgBase64);
            m.put("buildingName", x.getBuildingName());
            m.put("name", x.getName());
            m.put("phone", x.getPhone());
            m.put("wxAccount", x.getWxAccount());
            m.put("headImg", x.getHeadImg());
            return ResultUtil.ok(m);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取置业顾问个人主页小程序码失败", e);
            return ResultUtil.fail("获取小程序码失败");
        }
    }

    /**
     * 以流的方式返回置业顾问主页小程序码
     */
    public void getSellManHomePageQRCodeStream(int sellManCustomerId, HttpServletResponse rep) {
        SellManCachedBasicInfoBean x = this.cacheService.getSellManBasicInfo(sellManCustomerId);
        if (x == null)
            return;
        try {
            byte[] img = this.getHomePageQRCode(sellManCustomerId);
            if (img == null || img.length == 0)
                return;
            rep.getOutputStream().write(img);
            rep.getOutputStream().flush();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取置业顾问个人主页小程序码失败", e);
        } finally {
            try {
                rep.getOutputStream().close();
            } catch (IOException e) {
            }
        }

    }

    private byte[] getHomePageQRCode(int sellManCustomerId) throws Exception {
        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit"
                + "?access_token=" + getXiaoChengxuToken();
        Map<String, String> m = new HashMap<>();
        m.put("page", "pages/community/userIndex/main");
        m.put("scene", sellManCustomerId + "");
        HttpHeaders headers = new HttpHeaders();
        //设置请求媒体数据类型
        headers.setContentType(MediaType.APPLICATION_JSON);
        String json = JSON.toJSONString(m);
        HttpEntity<String> formEntity = new HttpEntity<String>(json, headers);
        ResponseEntity<byte[]> res = restTemplate.postForEntity(url, formEntity, byte[].class);
        byte[] x = res.getBody();
        return x;
    }

    private String getXiaoChengxuToken() {
        String url = "http://house-small-building/ms/building/getXiaoChengxuTk";
        String res = this.ribbonTemplate.getForObject(url, String.class);
        System.out.println(res);
        JSONObject jo = JSON.parseObject(res);
        return jo.getString("data");
    }

    public Object getYesterdayStarMicro(Integer buildingId) {
        List<SellManYesterdayStar> stars = this.cacheService.getYesterdayStars(null);
        if (stars == null) {
            // 初始化昨日之星
            updateYesterdayStar(null);
            stars = this.cacheService.getYesterdayStars(buildingId);
        }
        if (stars.size() == 0) {
            return ResultUtil.ok(0);
        }
        return ResultUtil.ok(stars.get(0).getCustomerId());
    }
}
